module ecs {
    /** 
     * 框架的主要实例。
     * 
     * 它包含了所有的系统。您必须使用它来创建、删除和检索实体。同样重要的是设置每个游戏循环迭代的增量，并在游戏循环之前初始化。
     */
    export class World {
        /** 管理世界上的所有实体 */
        private _em: EntityManager;
        private _alwaysDelayComponentRemoval: boolean;
        /** 管理世界上所有组件-实体关联 */
        private _cm: ComponentManager;
        /**
         * 从上次更新到现在已经过去的时间
         */
        public delta: number;
        /** 包含在进程上调用系统的策略 */
        public invocationStrategy: SystemInvocationStrategy;
        /** 实体编辑池 */
        public batchProcessor: BatchChangeProcessor;
        /** 管理世界的所有基于方面的实体订阅 */
        public asm: AspectSubscriptionManager;
        public partition: WorldSegment;
        /** 包含所有无序的系统 */
        public systemsBag: Bag<BaseSystem>;
        /**
         * 创造一个新世界
         * @param configuration 
         */
        constructor(configuration: WorldConfiguration){
            this.partition = new WorldSegment(configuration);
            this.systemsBag = configuration.systems;

            let lcm = <ComponentManager> this.systemsBag.get(WorldConfiguration.COMPONENT_MANAGER_IDX);
            let lem = <EntityManager> this.systemsBag.get(WorldConfiguration.ENTITY_MANAGER_IDX);
            let lasm = <AspectSubscriptionManager> this.systemsBag.get(WorldConfiguration.ASPECT_SUBSCRIPTION_MANAGER_IDX);

            this._cm = lcm == null ? new ComponentManager(configuration.expectedEntityCount()) : lcm;
            this._em = lem == null ? new EntityManager(configuration.expectedEntityCount()) : lem;
            this.asm = lasm == null ? new AspectSubscriptionManager() : lasm;

            this._alwaysDelayComponentRemoval = configuration.isAlwaysDelayComponentRemoval();
            this.batchProcessor = new BatchChangeProcessor(this);

            configuration.initialize(this, this.partition.injector, this.asm);
        }

        /**
         * 返回负责创建和维护的管理器
         */
        public getAspectSubscriptionManager(): AspectSubscriptionManager{
            return this.asm;
        }

        /**
         * 返回处理世界上所有组件的管理器
         */
        public getComponentManager(): ComponentManager{
            return this._cm;
        }

        /**
         * 返回一个管理器，该管理器负责管理世界上的所有实体。
         */
        public getEntityManager(): EntityManager{
            return this._em;
        }

        /**
         * 
         * @param type 
         */
        public getMapper<T>(type: T): ComponentMapper<T>{
            return this._cm.getMapper(type);
        }

        /**
         * 如果为true，则所有组件的组件移除将延迟，直到通知所有订阅
         */
        public isAlwaysDelayComponentRemoval(){
            return this._alwaysDelayComponentRemoval;
        }

        /**
         * 你必须在这里指定游戏的增量
         * @param delta 上次游戏循环后的时间
         */
        public setDelta(delta: number){
            this.delta = delta;
        }

        /**
         * 处理所有非被动系统。
         */
        public process(){
            this.invocationStrategy.process();
        }

        /**
         * 唯一的标识一个实体的组件组合。每个组合标识映射到一个唯一的BitVector
         * @param entityId 
         */
        public compositionId(entityId: number){
            return this._cm.getIdentity(entityId);
        }

        /**
         * 
         * @param invocationStrategy 
         */
        public setInvocationStrategy(invocationStrategy: SystemInvocationStrategy){
            this.invocationStrategy = invocationStrategy;
            invocationStrategy.setWorld(this);
            invocationStrategy.setSystems(this.systemsBag);
            invocationStrategy.initialize();
        }

        /**
         * 处理所有系统。只有当世界结束时才需要释放管理资源
         */
        public dispose(){
            for (let s in this.systemsBag){
                let system: BaseSystem = this.systemsBag[s];
                try {
                    system.dispose();
                } catch(err){
                    
                }
            }
        }

        /**
         * 创建并返回一个新的或重用的实体实例。实体被自动添加至世界中
         */
        public createEntity(): Entity{
            let e = this._em.createEntityInstance();
            this.batchProcessor.changed.unsafeSet(e.getId());
            return e;
        }
    }

    export class WorldSegment {
        /** 包含映射的所有系统和系统类 */
        public systems: Map<any, BaseSystem>;
        /** 负责依赖注入 */
        public injector: Injector;

        constructor(configuration: WorldConfiguration){
            this.systems = new Map<any, BaseSystem>([]);
            this.injector = (configuration.injector != null) ? configuration.injector : new CachedInjector();
        }
    }
}
